import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False

# 加载数据
df = pd.read_csv('./boston.csv')
# 对CRIM进行对数转换并分5级
df['CRIM_log'] = np.log(df['CRIM'])
df['CRIM_bin'] = pd.cut(df['CRIM_log'], bins=5, labels=False)

# 设置颜色映射，使颜色饱和度随犯罪率等级增加
cmap = sns.cubehelix_palette(5, start=2, rot=0, dark=0.3, light=0.8, as_cmap=True)

# 创建左右镜像的小提琴图
fig, axes = plt.subplots(1, 2, figsize=(12, 6))

# 左侧：犯罪率分布
sns.violinplot(x='CRIM_bin', data=df, ax=axes[0], palette=cmap)
axes[0].set_title('犯罪率分布（对数转换）')
axes[0].set_xlabel('犯罪率等级')
axes[0].set_ylabel('频率')

# 右侧：房价分布
sns.violinplot(x='CRIM_bin', y='MEDV', data=df, ax=axes[1], palette=cmap)
axes[1].set_title('房价分布')
axes[1].set_xlabel('犯罪率等级')
axes[1].set_ylabel('房价')

# 内嵌箱线图和均值点
for ax in axes:
    sns.boxplot(x='CRIM_bin', data=df, ax=ax, color='black', width=0.1)
    means = df.groupby('CRIM_bin')['MEDV'].mean() if ax == axes[1] else df.groupby('CRIM_bin')['CRIM_log'].mean()
    means.plot(kind='scatter', x=means.index, y=means.values, ax=ax, color='red')

# 添加核密度曲线说明文字（假设添加在图表下方）
plt.suptitle('不同犯罪率区间的房价分布形态', y=1.05)
plt.text(0.5, -0.2, "核密度曲线展示了不同犯罪率区间内房价/犯罪率的分布情况，曲线越宽表示数据分布越分散，越窄表示越集中。",
         ha='center', transform=plt.gca().transAxes)

# 使用暗色系突出高犯罪率区域（这里通过颜色映射本身实现一定程度突出）
# 若想进一步突出，可调整颜色映射或添加额外标注

plt.show()